
package com.example.filetransfer.connection;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import android.util.Log;

import com.example.filetransfer.connection.ClientListener.Server;
import com.example.filetransfer.publicsource.connection.DataReceiver;
import com.example.filetransfer.publicsource.connection.DataSender;
import com.example.filetransfer.publicsource.connection.FileTransferListener;
import com.example.filetransfer.publicsource.connection.NetBroadcast;
import com.example.filetransfer.publicsource.connection.NetBroadcastReceiver;
import com.example.filetransfer.publicsource.connection.DataReceiver.onReceiveMessageListener;
import com.example.filetransfer.publicsource.connection.NetBroadcastReceiver.MessageListener;
import com.example.filetransfer.publicsource.connection.Protocol;

public class ConnectionManager extends Thread {
    private static final String TAG = "ConnectionManager";
    private static ConnectionManager sInstance;
    private static final String EXTERNAL_SYNC_DIR = "/storage/emulated/legacy/Android/Data/com.example.filetransfer/files/syncs";
    private NetBroadcastReceiver mBroadcastReceiver;
    private ClientListener mClientListener;
    private Socket mSocket;
    private List<Server> mServers = new ArrayList<Server>();
    private Server mServer;
    private volatile boolean mError = false;

    private DataReceiver mDataReceiver;
    private DataSender mDataSender;

    protected ConnectionManager() {
        mBroadcastReceiver = new NetBroadcastReceiver(Protocol.BROADCAST_CLIENT_LISTEN_PORT);
        mBroadcastReceiver.setMessageListener(mBroadcastListener);
        mBroadcastReceiver.start();
    };

    public static synchronized ConnectionManager getInstance() {
        if (sInstance == null || sInstance.mError) {
            sInstance = new ConnectionManager();
        }
        return sInstance;
    }

    private MessageListener mBroadcastListener = new MessageListener() {
        @Override
        public void onNewMessageReceive(String message) {
            Log.d(TAG, "receive boradcast message:" + message);
            try {
                Server server = new Server();
                server.ip = Protocol.getIpFromAddressMessage(message);
                server.port = Protocol.getPortFromAddressMessage(message);
                mServers.add(server);
                mClientListener.onNewClientAccept(server);
            } catch (Exception e) {
                Log.e(TAG, "receive not ip address message ignor it");
            }
        }
    };

    public void setClientListener(ClientListener clientListener) {
        mClientListener = clientListener;
    }

    public interface OnConnectedListener {
        public void onConnect();
    }

    public OnConnectedListener mConnectedListener;

    public void startConnection(Server server,OnConnectedListener mConnectedListener) {
        this.mServer = server;
        this.mConnectedListener = mConnectedListener;
        mDataReceiver = new DataReceiver();
        mDataReceiver.setMessageListener(mMessageListener);
        mDataReceiver.setRootDir(EXTERNAL_SYNC_DIR);
        mDataSender = new DataSender(EXTERNAL_SYNC_DIR);
        start();
    }

    public onReceiveMessageListener mMessageListener = new onReceiveMessageListener() {
        @Override
        public void receiveMessage(String message) {
            if (mListener != null) {
                mListener.receiveMessage(message);
            }
        }
    };
    private onReceiveMessageListener mListener;

    public void requestClientConnect() {
        NetBroadcast.getInstance().sendBroadcast(Protocol.BROADCAST_SERVER_LISTEN_PORT,
                Protocol.MESSAGE_SEND_SERVER_ADDRESS);
    }

    public void notifyNewClient(Server server) {
        if (mClientListener != null) {
            mClientListener.onNewClientAccept(server);
        }
    }

    public void sendMessageToTarget(String message) {
        if (mDataSender != null) {
            mDataSender.sendMessage(message);
        }
    }

    public void sendFile(String file, FileTransferListener listener) throws FileNotFoundException {
        if (mDataSender != null) {
            mDataSender.sendFile(file, listener);
        }
    }

    public void setReceiveMessageListener(onReceiveMessageListener messageListener) {
        mListener = messageListener;
    }

    public void setFileTransferListener(FileTransferListener fileTransferListener) {
        mDataReceiver.setFileTransferListener(fileTransferListener);
    }

    public List<Server> getServerList() {
        return mServers;
    }

    @Override
    public void run() {
        try {
            mSocket = new Socket(mServer.ip, mServer.port);
            if (mConnectedListener != null)
                mConnectedListener.onConnect();
            mDataSender.setOutputStream(mSocket.getOutputStream());
            mDataSender.start();
            mDataReceiver.setInputStream(mSocket.getInputStream());
            mDataReceiver.run();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mError = true;
            close();
        }
    }

    public InputStream getInputStream(String ip) throws IOException {
        if (mSocket != null) {
            return mSocket.getInputStream();
        } else {
            return null;
        }
    }

    public OutputStream getOutputStream(String ip) throws IOException {
        if (mSocket != null) {
            return mSocket.getOutputStream();
        } else {
            return null;
        }
    }

    public void close() {
        if (mSocket != null) {
            try {
                mSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mDataSender != null) {
            mDataSender.release();
        }
        if (mDataReceiver != null) {
            mDataReceiver.release();
        }
    }
}
